home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / util / inetd / inetd.c next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  42.4 KB  |  1,692 lines

  1. RCS_ID_C="$Id: inetd.c,v 3.4 1994/05/02 19:43:59 jraja Exp $";
  2. /*
  3.  * inetd.c --- Internet super-server
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
  8.  *                  Helsinki University of Technology, Finland.
  9.  *                  All rights reserved.
  10.  *
  11.  * Created      : Mon May 24 00:34:11 1993 ppessi
  12.  * Last modified: Sat Feb 26 05:54:05 1994 ppessi
  13.  *
  14.  * $Log: inetd.c,v $
  15.  * Revision 3.4  1994/05/02  19:43:59  jraja
  16.  * Changed exitcode() to return 0 for concistency with other progs.
  17.  * Removed inclusion of the (removed) inetdlib.h.
  18.  *
  19.  * Revision 3.3  1994/04/25  14:51:19  jraja
  20.  * Fixed server argument parsing bugs.
  21.  *
  22.  * Revision 3.2  1994/02/26  09:23:56  ppessi
  23.  * Fixed SAS C 6.51 incompatibilities.
  24.  * Fixed bug in timer handling
  25.  *
  26.  * Revision 3.1  1994/02/24  03:35:35  ppessi
  27.  * Changed the VERSTAG and copyright formats slightly
  28.  *
  29.  * Revision 1.11  1993/10/21  01:51:20  ppessi
  30.  * Added correct prototype for CheckIO()
  31.  *
  32.  * Revision 1.10  1993/10/20  05:31:07  ppessi
  33.  * Using now gettimeofday().
  34.  *
  35.  * Revision 1.1  93/05/24  21:42:36  ppessi
  36.  * Original BSD code.
  37.  */
  38.  
  39. #include "inetd_rev.h"
  40. static const char version[] = VERSTAG " "
  41.      "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  42.                       "Helsinki University of Technology, Finland.\n"
  43. "@(#) Copyright © 1983 The Regents of the University of California.\n"
  44.                       "All rights reserved.\n";
  45.  
  46. /*
  47.  * Copyright (c) 1983,1991 The Regents of the University of California.
  48.  * All rights reserved.
  49.  *
  50.  * Redistribution and use in source and binary forms, with or without
  51.  * modification, are permitted provided that the following conditions
  52.  * are met:
  53.  * 1. Redistributions of source code must retain the above copyright
  54.  *    notice, this list of conditions and the following disclaimer.
  55.  * 2. Redistributions in binary form must reproduce the above copyright
  56.  *    notice, this list of conditions and the following disclaimer in the
  57.  *    documentation and/or other materials provided with the distribution.
  58.  * 3. All advertising materials mentioning features or use of this software
  59.  *    must display the following acknowledgement:
  60.  *    This product includes software developed by the University of
  61.  *    California, Berkeley and its contributors.
  62.  * 4. Neither the name of the University nor the names of its contributors
  63.  *    may be used to endorse or promote products derived from this software
  64.  *    without specific prior written permission.
  65.  *
  66.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  67.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  68.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  69.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  70.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  71.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  72.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  73.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  74.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  75.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  76.  * SUCH DAMAGE.
  77.  */
  78.  
  79. /****** netutil.doc/inetd ***************************************************
  80. *
  81. *  NAME
  82. *        inetd - internet ``super-server''
  83. *
  84. *  TEMPLATE
  85. *       inetd DEBUG/S CONFIGFILE
  86. *
  87. *  DESCRIPTION
  88. *
  89. *       Inetd should be run when the AmiTCP/IP protocol stack is started.
  90. *       Inetd listens for connections on certain internet sockets.  When a
  91. *       connection is found on one of its sockets, it decides what service the
  92. *       socket corresponds to, and invokes a program to service the request.
  93. *       After the program is finished, it continues to listen on the socket
  94. *       (except in some cases which will be described below).  Essentially,
  95. *       inetd allows running one daemon to invoke several others, reducing
  96. *       load on the system.
  97. *
  98. *  PARAMETERS
  99. *       DEBUG      Turns on debugging.
  100. *
  101. *       CONFIGFILE Specifies the configuration file name.
  102. *
  103. *  CONFIGURATION
  104. *
  105. *       Upon execution, inetd reads its configuration information from a
  106. *       configuration file which, by default, is AmiTCP:db/inetd.conf. There
  107. *       must be an entry for each field of the configuration file, with
  108. *       entries for each field separated by a tab or a space.  Comments are
  109. *       denoted by a ``#'' at the beginning of a line or ``;'' anywhere in the
  110. *       line. There must be an entry for each field. The fields of the
  111. *       configuration file are as follows:
  112. *
  113. *             service name
  114. *             socket type
  115. *             protocol
  116. *             wait/nowait
  117. *             user
  118. *             server program
  119. *             server program name
  120. *             server program arguments
  121. *
  122. *       The service-name entry is the name of a valid service in the
  123. *       netdatabase.  For ``internal'' services (discussed below), the service
  124. *       name must be the official name of the service.
  125. *
  126. *       The socket-type should be one of ``stream'', ``dgram'', ``raw'',
  127. *       ``rdm'', or ``seqpacket'', depending on whether the socket is a
  128. *       stream, datagram, raw, reliably delivered message, or sequenced packet
  129. *       socket. Current system supports only stream, datagram and raw
  130. *       protocols.
  131. *
  132. *       The protocol must be a valid protocol as given in netdatabase.
  133. *       Examples might be ``tcp'' or ``udp''.
  134. *
  135. *       The wait/nowait entry is useful for datagram sockets only (other
  136. *       sockets should have a ``nowait'' entry in this space).  If a datagram
  137. *       server connects to its peer, freeing the socket so inetd can received
  138. *       further messages on the socket, it is said to be a ``multi-threaded''
  139. *       server, and should use the ``nowait'' entry.  For datagram servers
  140. *       which process all incoming datagrams on a socket and eventually time
  141. *       out, the server is said to be ``single-threaded'' and should use a
  142. *       ``wait'' entry.  Comsat and talkd are both examples of the latter type
  143. *       of datagram server.
  144. *
  145. *       The user entry should contain the user name of the user as whom the
  146. *       server should run. This field is for Unix and future compability
  147. *       only.
  148. *
  149. *       The server-program entry should contain the pathname of the program
  150. *       which is to be executed by inetd when a request is found on its
  151. *       socket.  If the server program is resident, the path name should be
  152. *       suppressed. If inetd provides this service internally, this entry
  153. *       should be ``internal''.
  154. *
  155. *       The server-program-name is CLI command name for the server process. It
  156. *       is shown in the printout of ``status'' command. (Task name of the
  157. *       server process is the service and the peer address, e.g. ``echo
  158. *       [192.233.15.19]''.) This and argument entry are optional.
  159. *
  160. *       The server program arguments should be just as arguments normally are.
  161. *
  162. *       Inetd provides several ``trivial'' services internally by use of
  163. *       routines within itself.  These services are ``echo'', ``discard'',
  164. *       ``chargen'' (character generator), ``daytime'' (human readable time),
  165. *       and ``time'' (machine readable time, in the form of the number of
  166. *       seconds since mid­ night, January 1, 1900).  All of these services are
  167. *       TCP and UDP based.  For details of these services, consult the
  168. *       appropriate RFC from the Network Information Center.
  169. *
  170. *       Inetd rereads its configuration file when it receives the CTRL-F
  171. *       signal.  Services may be added, deleted or modified when the
  172. *       configuration file is reread.
  173. *
  174. *  HISTORY
  175. *       The inetd command appeared in 4.3BSD system.
  176. *
  177. *  SEE ALSO
  178. *
  179. *****************************************************************************
  180. *
  181. */
  182.  
  183. /*
  184.  * Inetd - Internet super-server
  185.  *
  186.  * This program invokes all internet services as needed.
  187.  * connection-oriented services are invoked each time a connection is
  188.  * made, by creating a process. Created server process is passed the
  189.  * connection as file descriptor 0 and is expected to do a getpeername
  190.  * to find out the source host and port.
  191.  *
  192.  * Datagram oriented services are invoked when a datagram arrives; a
  193.  * process is created and passed a pending message on file descriptor
  194.  * 0. Datagram servers may either connect to their peer, freeing up
  195.  * the original socket for inetd to receive further messages on, or
  196.  * ``take over the socket'', processing all arriving datagrams and,
  197.  * eventually, timing out. The first type of server is said to
  198.  * be ``multi-threaded''; the second type of server
  199.  * ``single-threaded''.
  200.  *
  201.  * Inetd uses a configuration file which is read at startup and,
  202.  * possibly, at some later time in response to a signal CTRL_F.  The
  203.  * configuration file is parsed with standard DOS functions with
  204.  * template given below. Multiple line entries must have a ``+'' char at
  205.  * the end of the file.
  206.  *
  207.  *     service             must be in /etc/services
  208.  *    socket type            stream/dgram/raw/rdm/seqpacket
  209.  *    protocol            must be in /etc/protocols
  210.  *    dowait                    single-threaded/multi-threaded
  211.  *    user                user to run daemon as
  212.  *    server program            full path name
  213.  *    server program name        CLI command name (optional)
  214.  *    server program arguments    Normal command argument line 
  215.  *
  216.  * Comment lines are indicated by a `#' in column 1. 
  217.  */
  218.  
  219. #include <sys/param.h>
  220. #include <sys/stat.h>
  221. #include <sys/ioctl.h>
  222. #include <sys/socket.h>
  223. #include <sys/time.h>
  224.  
  225. #include <netinet/in.h>
  226. #include <arpa/inet.h>
  227.  
  228. #include <errno.h>
  229. #include <signal.h>
  230. #include <netdb.h>
  231. #include <stdio.h>
  232. #include <string.h>
  233. #include <stdlib.h>
  234. #include <time.h>
  235. #include <stdarg.h>
  236. #include <syslog.h>
  237.  
  238. #ifdef AMIGA
  239. #include <exec/execbase.h>
  240. #include <exec/memory.h>
  241. #include <devices/timer.h>
  242. #include <dos/dostags.h>
  243. extern struct ExecBase *SysBase;
  244. #if __SASC
  245. #include <proto/socket.h>
  246. #include <proto/dos.h>
  247. #include <clib/exec_protos.h>
  248. #include <pragmas/exec_sysbase_pragmas.h>
  249. #include <pragmas/timer_pragmas.h>
  250. /* #elif __GNUC__
  251. #include <inline/socket.h>
  252. #include <inline/exec.h>
  253. */
  254. #else 
  255. #error Unsupported compiler
  256. #include <clib/socket_protos.h>
  257. #endif
  258.  
  259. /* Correct prototype for the CheckIO.
  260.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  261.  * instead of a pointer (32 bits)!)
  262.  */
  263. struct IORequest * CheckIO(struct IORequest *req);
  264. #else /* def AMIGA */
  265. #include <pwd.h>
  266. #include <sys/file.h>
  267. #include <sys/wait.h>
  268. #include <sys/resource.h>
  269. #endif
  270.  
  271. #include "inetd.h"
  272.  
  273. /* don't start more than TOOMANY servers in CNT_INTVL seconds */
  274. #define    TOOMANY        10
  275. #define    CNT_INTVL    60        
  276.  
  277. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  278.  
  279. #define INETDNAME "inetd"
  280.  
  281. #define MAXARGS 8
  282. enum fileargs 
  283.   service = 0, socket_type, protocol, wait, user, server, cmdname, arguments
  284. };
  285. #define TYPETEMPLATE "stream,dgram,raw,rdm,seqpacket"
  286. #define WAITTEMPLATE "nowait,wait"
  287.  
  288. void reapchild(void);
  289. void startserver(register struct servtab *sep, long ctrl);
  290. void askalarm(long seconds);
  291. void getalarm(void);
  292. void config(void);
  293. void retry(void);
  294. void setup(register struct servtab *sep);
  295. struct servtab *enter(struct servtab *cp);
  296.  
  297. int setconfig(void);
  298. struct servtab *getconfigent(void);
  299. void freeconfig(register struct servtab *cp);
  300. void endconfig(void);
  301. void print_service(char *action, struct servtab *sep);
  302.  
  303. ASM LONG exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage);
  304. LONG start_builtin(void);
  305. void setproctitle(char *a, int s);
  306.  
  307. UBYTE *proctitle(char *a, int s);
  308. void  amigainit(void);
  309. void amigadeinit(void);
  310. static ULONG csprintf(struct CSource *buf, const char *fmt, ...);
  311.  
  312. int    nsock = 0, maxsock = 0;
  313. fd_set    allsock;
  314. int    options = 0;
  315. struct    servent *sp = NULL;
  316.  
  317. /* 
  318.  * We create a "process table" for builtins, because they 
  319.  * must be waited as they use the same code segment as we do 
  320.  */
  321. #define MAX_BUILTIN_PROC 16
  322. int builtins_started = 0;
  323. long ptable[MAX_BUILTIN_PROC] = { 0 };
  324.  
  325. struct DaemonPort *dport = NULL;
  326.  
  327. #define DO_WAIT   ((struct DaemonMessage *)1)
  328. #define DONT_WAIT ((struct DaemonMessage *)NULL)
  329.  
  330. struct MsgPort *tport = NULL;
  331. struct timerequest *tmsg = NULL;
  332. int   timer_is_open = 0;
  333. #define TimerBase (tmsg->tr_node.io_Device)
  334.  
  335. struct    servtab {
  336.     char    *se_service;        /* name of service */
  337.     long    se_socktype;        /* type of socket to use */
  338.     char    *se_proto;        /* protocol used */
  339.     struct     DaemonMessage *se_wait; /* single threaded server */
  340.     char    *se_user;        /* user name to run as */
  341.     struct    biltin *se_bi;        /* if built-in, description */
  342.     char    *se_server;        /* server program */
  343.     char    *se_argv0;            /* cli name for daemon */
  344.     char    *se_argv;            /* program arguments */
  345.     long    se_fd;            /* open descriptor */
  346.     struct    sockaddr_in se_ctrladdr;/* bound address */
  347.     struct    timeval se_time;    /* start of se_count */
  348.     struct    servtab *se_next;
  349.     short    se_checked;        /* looked at during merge */
  350.     short    se_count;        /* number started since se_time */
  351. } *servtab;
  352.  
  353. /* 
  354.  * Internal Services 
  355.  *
  356.  * Because Data Segment is *not* duplicated by CreateNewProc 
  357.  * server routines must be re-entrable and not touch global data
  358.  */ 
  359. int echo_stream(void *SocketBase, int s, struct servtab *sep);
  360. int echo_dg(void *SocketBase, int s, struct servtab *sep);
  361. int discard_stream(void *SocketBase, int s, struct servtab *sep);
  362. int discard_dg(void *SocketBase, int s, struct servtab *sep); 
  363. int machtime_stream(void *SocketBase, int s, struct servtab *sep);
  364. int machtime_dg(void *SocketBase, int s, struct servtab *sep); 
  365. int daytime_stream(void *SocketBase, int s, struct servtab *sep);
  366. int daytime_dg(void *SocketBase, int s, struct servtab *sep);
  367. int chargen_stream(void *SocketBase, int s, struct servtab *sep);
  368. int chargen_dg(void *SocketBase, int s, struct servtab *sep);
  369.  
  370. struct biltin {
  371.     char    *bi_service;        /* internally provided service name */
  372.     int    bi_socktype;        /* type of socket supported */
  373.     int    bi_process;        /* 1 if should start a process */
  374.     struct    DaemonMessage *bi_wait;    /* DO_WAIT if should wait for child */
  375.     int    (*bi_fn)(void *SocketBase, int s, struct servtab *sep);
  376.                         /* function which performs it */
  377. } biltins[] = {
  378.     /* Echo received data */
  379.     "echo",        SOCK_STREAM,    1, DONT_WAIT,    echo_stream,
  380.     "echo",        SOCK_DGRAM,    0, DONT_WAIT,    echo_dg,
  381.  
  382.     /* Internet /dev/null */
  383.     "discard",    SOCK_STREAM,    1, DONT_WAIT,    discard_stream,
  384.     "discard",    SOCK_DGRAM,    0, DONT_WAIT,    discard_dg,
  385.  
  386.     /* Return 32 bit time since 1970 */
  387.     "time",        SOCK_STREAM,    0, DONT_WAIT,    machtime_stream,
  388.     "time",        SOCK_DGRAM,    0, DONT_WAIT,    machtime_dg,
  389.  
  390.     /* Return human-readable time */
  391.     "daytime",    SOCK_STREAM,    0, DONT_WAIT,    daytime_stream,
  392.     "daytime",    SOCK_DGRAM,    0, DONT_WAIT,    daytime_dg,
  393.  
  394.     /* Familiar character generator */
  395.     "chargen",    SOCK_STREAM,    1, DONT_WAIT,    chargen_stream,
  396.     "chargen",    SOCK_DGRAM,    0, DONT_WAIT,    chargen_dg,
  397.     0
  398. };
  399.  
  400. /* Internal buffer size. Allocated from stack */
  401. #define    BUFSIZE    8192
  402.  
  403. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  404.  
  405. int debug;
  406. char *CONFIG = _PATH_INETDCONF;
  407.  
  408. main(void)
  409. {
  410.   register struct servtab *sep;
  411.   ULONG events;
  412.   ULONG mask;
  413.  
  414.   {
  415.     LONG Argv[2];
  416.     struct RDArgs *rdargs;
  417.  
  418.     Argv[0] = Argv[1] = 0;
  419.     rdargs = ReadArgs("DEBUG/S,CONFIGFILE", Argv, NULL);
  420.  
  421.     if (!rdargs) {
  422.       PrintFault(IoErr(), "ReadArgs");
  423.       exit(1);
  424.     }
  425.     debug = Argv[0];
  426.     if (Argv[1])
  427.       CONFIG = strdup((char *)Argv[1]);
  428.  
  429.     FreeArgs(rdargs);
  430.   }
  431.  
  432.   if (debug) {
  433.     options |= SO_DEBUG;
  434.   } else {
  435. #if 0
  436.     daemon(0, 0);
  437. #endif
  438.   }
  439.  
  440.   openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  441.  
  442.   amigainit();
  443.  
  444.   events = 1 << (dport->dp_Port.mp_SigBit) | 1 << (tport->mp_SigBit) 
  445.     | SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C;
  446.   SetSocketSignals(0L, 0L, 0L); /* no no no no no no there is no EINTR */
  447.  
  448.   config();
  449.  
  450.   for (;;) {
  451.     int n, ctrl;
  452.     fd_set readable;
  453.  
  454.     mask = events;
  455.     readable = allsock;
  456.     if ((n = WaitSelect(maxsock + 1, &readable, (fd_set *)NULL,
  457.             (fd_set *)NULL, (struct timeval *)NULL, &mask)) < 0) {
  458.       if (errno != EINTR)
  459.     syslog(LOG_WARNING, "select: %s", strerror(errno));
  460.       continue;
  461.     }
  462.  
  463.     if (mask & SIGBREAKF_CTRL_F) {
  464.       config();
  465.     }
  466.  
  467.     if (mask & SIGBREAKF_CTRL_C) {
  468.       exit(0);
  469.     }
  470.  
  471.     if (mask & (1<<(tport->mp_SigBit))) {
  472.       getalarm();
  473.     }
  474.  
  475.     if (mask & (1<<(dport->dp_Port.mp_SigBit))) {
  476.       reapchild();
  477.     }
  478.  
  479.     for (sep = servtab; n && sep; sep = sep->se_next)
  480.       if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  481.     n--;
  482.     if (debug)
  483.       fprintf(stderr, "someone wants %s\n", sep->se_service);
  484.     if (sep->se_socktype == SOCK_STREAM) {
  485.       ctrl = accept(sep->se_fd, NULL, NULL);
  486.       if (debug)
  487.         fprintf(stderr, "accept, ctrl %ld\n", ctrl);
  488.       if (ctrl < 0) {
  489.         if (errno != EINTR)
  490.           syslog(LOG_WARNING, "accept (for %s): %s", 
  491.              sep->se_service, strerror(errno));
  492.         continue;
  493.       }
  494.     } else
  495.       ctrl = sep->se_fd;
  496.     if (sep->se_bi == 0 || sep->se_bi->bi_process) {
  497.       startserver(sep, ctrl);
  498.     } else {
  499.       (*sep->se_bi->bi_fn)(SocketBase, ctrl, sep);
  500.       if (sep->se_socktype == SOCK_STREAM)
  501.         CloseSocket(ctrl);
  502.     }
  503.       }
  504.   }
  505. }
  506.  
  507. /*
  508.  * startserver:
  509.  *      Launch a new process to handle service
  510.  */
  511. void 
  512. startserver( register struct servtab *sep, long ctrl)
  513. {
  514.   LONG id;
  515.   struct DaemonMessage *dm = CreateIORequest(dport, sizeof(*dm));
  516.   UBYTE *dname = proctitle(sep->se_service, ctrl);
  517.   int ok = 0;
  518.  
  519.   if (!dm || !dname) { 
  520.     syslog(LOG_ERR, "inetd exhausted memory, exits");
  521.     if (dm) DeleteIORequest(dm);
  522.     if (dname) FreeVec(dname);
  523.     exit(1);
  524.   }
  525.  
  526.   if (sep->se_count++ == 0) {
  527.     (void)gettimeofday(&sep->se_time, (struct timezone *)0);
  528.   } else if (sep->se_count >= TOOMANY) {
  529.     struct timeval now;
  530.     (void)gettimeofday(&now, (struct timezone *)0);
  531.     if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
  532.       sep->se_time = now;
  533.       sep->se_count = 1;
  534.     } else {
  535.       syslog(LOG_ERR, "%s/%s server failing (looping), "
  536.          "service terminated\n", sep->se_service, sep->se_proto);
  537.       FD_CLR(sep->se_fd, &allsock);
  538.       (void) CloseSocket(sep->se_fd);
  539.       sep->se_fd = -1;
  540.       sep->se_count = 0;
  541.       nsock--;
  542.       askalarm(RETRYTIME);
  543.     }
  544.   }
  545.  
  546.   if (sep->se_socktype == SOCK_STREAM)
  547.     id = ReleaseSocket(ctrl, -1);
  548.   else
  549.     id = ReleaseCopyOfSocket(ctrl, -1);
  550.  
  551.   if (dm != NULL && id != -1) {
  552.     dm->dm_Msg.mn_Node.ln_Name = dname;
  553.     dm->dm_Id = id;
  554.     dm->dm_Family = AF_INET;
  555.     dm->dm_Type = sep->se_socktype;
  556.  
  557.     if (sep->se_bi) {
  558.       struct Process *pid = NULL;
  559.       /* 
  560.        * Start a built in function
  561.        */
  562.       dm->dm_Retval = (LONG)sep;
  563.       dm->dm_Type = DMTYPE_INTERNAL;
  564.       if (builtins_started < MAX_BUILTIN_PROC) {
  565.     pid =
  566.       CreateNewProcTags(NP_Entry, start_builtin, NP_StackSize, BUFSIZE*2,
  567.                 NP_ExitCode, exitcode, NP_ExitData, dm,
  568.                 NP_Priority, -10,
  569.                 dname ? NP_Name : TAG_DONE, dname,
  570.                 TAG_DONE);
  571.     ok = pid != NULL;
  572.     if (ok) {
  573.       dm->dm_Pid = pid; 
  574.       ptable[builtins_started++] = (long)pid;
  575.     }
  576.       }
  577.     } else {
  578.       /*
  579.        * Start an external process
  580.        */
  581.       BPTR input = Open("NIL:", MODE_OLDFILE);
  582.       BPTR output = Open("NIL:", MODE_OLDFILE);
  583. #if 1
  584.       BPTR seglist;
  585.       struct Segment *sl;
  586.  
  587.       /* Try to find seglist from resident list */
  588.       Forbid();
  589.       if (sl = FindSegment(sep->se_server, NULL, FALSE)) {
  590.     if (sl->seg_UC >= 0) {
  591.       sl->seg_UC++;
  592.       dm->dm_Seg = sl;        /* must be freed */
  593.     } else if (sl->seg_UC != -2) {
  594.       sl = NULL;
  595.     }
  596.       }
  597.       Permit();
  598.  
  599.       if (sl)
  600.     seglist = sl->seg_Seg;
  601.       else
  602.     seglist = NewLoadSegTags(sep->se_server, TAG_DONE);
  603.  
  604.       if (input && output && seglist) {
  605.     ok = (int)
  606.       CreateNewProcTags(NP_Seglist, seglist,
  607.                 NP_FreeSeglist, sl == NULL,
  608.                 NP_Cli, TRUE, 
  609.                 NP_CommandName, sep->se_argv0,
  610.                 NP_Arguments, sep->se_argv, 
  611.                 NP_Input, input, 
  612.                 NP_Output, output,
  613.                 NP_StackSize, BUFSIZE*2, 
  614.                 NP_Priority, -10, 
  615.                 NP_ExitCode, dport->dp_ExitCode,
  616.                 NP_ExitData, dm, 
  617.                 dname ? NP_Name : TAG_END, dname,
  618.                 TAG_END, NULL);
  619.       }
  620.       if (!ok) {
  621.     if (seglist) UnLoadSeg(seglist);
  622.     if (input) Close(input);
  623.     if (output) Close(output);
  624.       }
  625.     }
  626. #else
  627.       if (input && output) {
  628.     ok = !SystemTags(sep->se_argv,
  629.              SYS_Asynch, 1, SYS_UserShell, 1,
  630.              SYS_Input, input, SYS_Output, output,
  631.              NP_StackSize, BUFSIZE*2,
  632.              NP_ExitCode, exitcode, NP_ExitData, dm,
  633.              NP_Priority, -10, 
  634.              dname ? NP_Name : TAG_END, dname,
  635.              TAG_END, NULL);
  636.       }
  637.       if (!ok) {
  638.     if (input) Close(input);
  639.     if (output) Close(output);
  640.       }
  641.     }
  642. #endif
  643.     if (ok && sep->se_wait) {
  644.       sep->se_wait = dm;
  645.       if (sep->se_fd >= 0) {
  646.     FD_CLR(sep->se_fd, &allsock);
  647.     nsock--;
  648.       }
  649.     }
  650.   }
  651.  
  652.   /* Clean up */
  653.   if (!ok) {
  654.     /* Drop the pending datagram */
  655.     char buf[32];
  656.     if (sep->se_socktype != SOCK_STREAM)
  657.       recv(ctrl, buf, sizeof (buf), 0);
  658.  
  659.     if (dm) DeleteIORequest(dm);
  660.     if (dname) FreeVec(dname);
  661.     if (id != -1) {
  662.       ctrl = ObtainSocket(id, AF_INET, sep->se_socktype, 0);
  663.       if (ctrl >= 0) CloseSocket(ctrl);
  664.     }
  665.   }
  666. }
  667.  
  668. /*
  669.  * reapchild: 
  670.  *      handle death messages from childs
  671.  */
  672. void
  673. reapchild(void)
  674. {
  675.   struct DaemonMessage *dm;
  676.  
  677.   while (dm = (struct DaemonMessage *)GetMsg(dport)) {
  678.     long status = dm->dm_Retval;
  679.     register struct servtab *sep;
  680.  
  681.     if (debug)
  682.       fprintf(stderr, "reaped child %s\n", dm->dm_Msg.mn_Node.ln_Name);
  683.     for (sep = servtab; sep; sep = sep->se_next)
  684.       if (sep->se_wait == dm) {
  685.     if (status)
  686.       syslog(LOG_WARNING,
  687.          "%s: exit status 0x%lx",
  688.          sep->se_server, status);
  689.     if (debug)
  690.       fprintf(stderr, "restored %s, fd %ld\n",
  691.           sep->se_service, sep->se_fd);
  692.     FD_SET(sep->se_fd, &allsock);
  693.     nsock++;
  694.     sep->se_wait = DO_WAIT;
  695.       }
  696.  
  697.     /* update "process table" */ 
  698.     if (dm->dm_Type == DMTYPE_INTERNAL) {
  699.       long pid = (long)dm->dm_Pid;
  700.       int i = --builtins_started;
  701.       for (i; i >= 0; i--) 
  702.     if (pid = ptable[i]) {
  703.       ptable[i] = ptable[builtins_started];
  704.       break;
  705.     }
  706.       if (i < 0) {
  707.     syslog(LOG_ALERT, "inetd: unknown internal daemon 0x%lx", pid);
  708.     builtins_started++;
  709.       }
  710.     }
  711.     /* Free resources allocated for the daemon */
  712.     if (dm->dm_Seg) {
  713.       Forbid();
  714.       dm->dm_Seg->seg_UC--;
  715.       Permit();
  716.     }
  717.     if (dm->dm_Msg.mn_Node.ln_Name)
  718.       FreeVec(dm->dm_Msg.mn_Node.ln_Name);
  719.     DeleteIORequest(dm);
  720.   }
  721. }
  722.  
  723. /*
  724.  * config:
  725.  *      configure services
  726.  */
  727. void
  728. config(void)
  729. {
  730.   register struct servtab *sep, *cp, **sepp;
  731.  
  732.   if (!setconfig()) {
  733.     endconfig();
  734.     return;
  735.   }
  736.  
  737.   for (sep = servtab; sep; sep = sep->se_next)
  738.     sep->se_checked = 0;
  739.   while (cp = getconfigent()) {
  740.     for (sep = servtab; sep; sep = sep->se_next)
  741.       if (strcmp(sep->se_service, cp->se_service) == 0 &&
  742.       strcmp(sep->se_proto, cp->se_proto) == 0)
  743.     break;
  744.     if (sep != 0) {
  745.       freeconfig(sep);
  746.       /*
  747.        * sep->se_wait may be holding the "pid" of a daemon
  748.        * that we're waiting for.  If so, don't overwrite
  749.        * it unless the config file explicitly says don't 
  750.        * wait.
  751.        */
  752.       if (cp->se_bi == 0 && 
  753.       (sep->se_wait == DO_WAIT || cp->se_wait == DONT_WAIT))
  754.     sep->se_wait  = cp->se_wait;
  755.       sep->se_service = cp->se_service;
  756.       sep->se_proto   = cp->se_proto;
  757.       sep->se_user    = cp->se_user;
  758.       sep->se_server  = cp->se_server;
  759.       sep->se_argv    = cp->se_argv;
  760.       if (debug)
  761.     print_service("REDO", sep);
  762.     } else {
  763.       sep = enter(cp);
  764.       if (debug)
  765.     print_service("ADD ", sep);
  766.     }
  767.     sep->se_checked = 1;
  768.     sp = getservbyname(sep->se_service, sep->se_proto);
  769.     if (sp == 0) {
  770.       syslog(LOG_ERR, "%s/%s: unknown service",
  771.          sep->se_service, sep->se_proto);
  772.       if (sep->se_fd != -1)
  773.     (void) CloseSocket(sep->se_fd);
  774.       sep->se_fd = -1;
  775.       continue;
  776.     }
  777.     if (sp->s_port != sep->se_ctrladdr.sin_port) {
  778.       sep->se_ctrladdr.sin_port = sp->s_port;
  779.       if (sep->se_fd != -1)
  780.     (void) CloseSocket(sep->se_fd);
  781.       sep->se_fd = -1;
  782.     }
  783.     if (sep->se_fd == -1)
  784.       setup(sep);
  785.   }
  786.   endconfig();
  787.   /*
  788.    * Purge anything not looked at above.
  789.    */
  790.   sepp = &servtab;
  791.   while (sep = *sepp) {
  792.     if (sep->se_checked) {
  793.       sepp = &sep->se_next;
  794.       continue;
  795.     }
  796.     *sepp = sep->se_next;
  797.     if (sep->se_fd != -1) {
  798.       FD_CLR(sep->se_fd, &allsock);
  799.       nsock--;
  800.       (void) CloseSocket(sep->se_fd);
  801.     }
  802.     if (debug)
  803.       print_service("FREE", sep);
  804.     freeconfig(sep);
  805.     free((char *)sep);
  806.   }
  807. }
  808.  
  809. /*
  810.  * askalarm:
  811.  *      ask for timeout
  812.  */
  813. void 
  814. askalarm(long seconds) 
  815. {
  816.   if (tmsg->tr_node.io_Message.mn_Node.ln_Type == NT_UNKNOWN 
  817.       || CheckIO(tmsg)) {
  818.     tmsg->tr_time.tv_secs = seconds;
  819.     tmsg->tr_time.tv_micro = 0;
  820.     SendIO(tmsg);
  821.   }
  822. }
  823.  
  824. /*
  825.  * getalarm:
  826.  *      handle timeouts
  827.  */
  828. void 
  829. getalarm(void) 
  830. {
  831.   struct Message *msg;
  832.   while (msg = GetMsg(tport)) {
  833.     if ((struct timerequest *)msg == tmsg) {
  834.       tmsg->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN; 
  835.       retry();
  836.       continue;
  837.     }
  838.   }
  839. }
  840.  
  841. /*
  842.  * retry:
  843.  *      try to setup all configured services
  844.  */
  845. void
  846. retry(void)
  847. {
  848.   register struct servtab *sep;
  849.  
  850.   for (sep = servtab; sep; sep = sep->se_next)
  851.     if (sep->se_fd == -1)
  852.       setup(sep);
  853. }
  854.  
  855. /*
  856.  * setup:
  857.  *      open a socket for given port
  858.  */
  859. void
  860. setup(register struct servtab *sep)
  861. {
  862.   int on = 1;
  863.  
  864.   if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  865.     syslog(LOG_ERR, "%s/%s: socket: %s",
  866.        sep->se_service, sep->se_proto, strerror(errno));
  867.     return;
  868.   }
  869. #define    turnon(fd, opt) \
  870.   setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  871.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  872.     turnon(sep->se_fd, SO_DEBUG) < 0)
  873.       syslog(LOG_ERR, "setsockopt (SO_DEBUG): %s", strerror(errno));
  874.   if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  875.     syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %s", strerror(errno));
  876. #undef turnon
  877.   if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  878.        sizeof (sep->se_ctrladdr)) < 0) {
  879.     syslog(LOG_ERR, "%s/%s: bind: %s",
  880.        sep->se_service, sep->se_proto, strerror(errno));
  881.     (void) CloseSocket(sep->se_fd);
  882.     sep->se_fd = -1;
  883.     askalarm(RETRYTIME);
  884.     return;
  885.   }
  886.   if (sep->se_socktype == SOCK_STREAM)
  887.     listen(sep->se_fd, 10);
  888.   FD_SET(sep->se_fd, &allsock);
  889.   nsock++;
  890.   if (sep->se_fd > maxsock)
  891.     maxsock = sep->se_fd;
  892. }
  893.  
  894. /*
  895.  * enter:
  896.  *      Allocate a new server entry
  897.  */ 
  898. struct servtab *
  899. enter(struct servtab *cp)
  900. {
  901.   register struct servtab *sep;
  902.  
  903.   sep = (struct servtab *)malloc(sizeof (*sep));
  904.   if (sep == (struct servtab *)0) {
  905.     syslog(LOG_ERR, "Out of memory.");
  906.     exit(20);
  907.   }
  908.   *sep = *cp;
  909.   sep->se_fd = -1;
  910.   sep->se_next = servtab;
  911.   servtab = sep;
  912.  
  913.   return (sep);
  914. }
  915.  
  916. /*
  917.  * print_service:
  918.  *    Dump relevant information to stderr
  919.  */
  920. void
  921. print_service(char *action, struct servtab *sep)
  922. {
  923.   fprintf(stderr, "%s: %s proto=%s, "
  924.       "wait=%ld, user=%s builtin=0x%lx server=%s\n",
  925.       action, sep->se_service, sep->se_proto,
  926.       sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  927. }
  928.  
  929.  
  930. /* 
  931.  * Functions to read configuration file
  932.  */
  933.  
  934. BPTR    fconfig = NULL;
  935. long    linecnt = 0;
  936. struct    servtab serv;
  937. #define LINEBUFLEN 1024
  938. char    *linbuf = NULL;
  939. struct  CSource    line = { 0, 0, 0 };
  940. struct RDArgs *largs = NULL;
  941.  
  942. void logdoserror(const char *banner);
  943. struct CSource * nextline(BPTR fh);
  944.  
  945. int
  946. setconfig(void)
  947. {
  948.   linecnt = 0;
  949.  
  950.   if (!linbuf) 
  951.     linbuf = malloc(LINEBUFLEN);
  952.  
  953.   if (!largs) 
  954.     largs = AllocDosObject(DOS_RDARGS, NULL);
  955.  
  956.   if (fconfig != NULL) {
  957.     Seek(fconfig, 0L, OFFSET_BEGINNING);
  958.   } else {
  959.     fconfig = Open(CONFIG, MODE_OLDFILE);
  960.     if (!fconfig) logdoserror("setconfig");
  961.   }
  962.   return (fconfig != NULL && linbuf != NULL && largs != NULL);
  963. }
  964.  
  965. void
  966. endconfig(void)
  967. {
  968.   if (fconfig) {
  969.     (void) Close(fconfig);
  970.     fconfig = NULL;
  971.   }
  972. #if 0
  973.   if (linbuf) {
  974.     free(linbuf);
  975.     linbuf = NULL;
  976.   }
  977. #endif
  978.   if (largs) {
  979.     FreeDosObject(DOS_RDARGS, largs);
  980.     largs = NULL;
  981.   }
  982. }
  983.  
  984. struct servtab *
  985. getconfigent(void)
  986. {
  987.   register struct servtab *sep = &serv;
  988.   struct CSource *cp;
  989.  
  990.  more:
  991.   while ((cp = nextline(fconfig)) && 
  992.      (cp->CS_Buffer[0] == '#' || cp->CS_Buffer[0] == ';'))
  993.     ;
  994.   if (cp == NULL)
  995.     return NULL;
  996.  
  997.   {
  998.     short len, i, item;
  999.     char *old, *new; 
  1000.     UBYTE *argv[MAXARGS];
  1001.     UBYTE argbuf[LINEBUFLEN];
  1002.  
  1003.     /* Parse line */
  1004.     for (len = i = 0; i < MAXARGS - 1; i++) {
  1005.       argv[i] = argbuf + len;
  1006.       item = (short)ReadItem(argbuf + len, sizeof(argbuf) - len, cp);
  1007.       if (item < 0) {
  1008.     logdoserror("ReadItem");
  1009.     return NULL;
  1010.       } else if (item == ITEM_NOTHING) {
  1011.     for (; i < MAXARGS - 1; i++) {
  1012.       argv[i] = " ";
  1013.       len += 2;
  1014.     }
  1015.     break;
  1016.       } else {
  1017.     len += strlen(argv[i]) + 1;
  1018.       }
  1019.     }
  1020.     if (i == MAXARGS - 1) { /* arguments to the server */
  1021.       argv[i] = cp->CS_Buffer + cp->CS_CurChr;
  1022.       len += strlen(argv[i]) + 1;
  1023.     }
  1024.  
  1025.     sep->se_socktype = FindArg(TYPETEMPLATE, (STRPTR)argv[socket_type]) + 1;
  1026.     if (sep->se_socktype == 0) 
  1027.       sep->se_socktype = DMTYPE_UNKNOWN;
  1028.  
  1029.     switch (FindArg(WAITTEMPLATE, (STRPTR)argv[wait])) {
  1030.     case -1:
  1031.       /* A error message might be cool */
  1032.     case 0:
  1033.       sep->se_wait = DONT_WAIT;
  1034.       break;
  1035.     case 1:
  1036.       sep->se_wait = DO_WAIT;
  1037.       break;
  1038.     }
  1039.  
  1040.     new = malloc(len);
  1041.     if (!new) {
  1042.       SetIoErr(ERROR_NO_FREE_STORE);
  1043.       logdoserror("getconfigent");
  1044.       return NULL;
  1045.     }
  1046.  
  1047.     sep->se_service = new; 
  1048.     old = (char *)argv[service]; while (*new++ = *old++); 
  1049.     sep->se_proto = new;
  1050.     old = (char *)argv[protocol]; while (*new++ = *old++); 
  1051.     sep->se_user = new;
  1052.     old = (char *)argv[user]; while (*new++ = *old++); 
  1053.     sep->se_server = new;
  1054.     old = (char *)argv[server]; while (*new++ = *old++); 
  1055.     sep->se_argv0 = new;
  1056.     old = (char *)argv[cmdname]; while (*new++ = *old++); 
  1057.     sep->se_argv = new;
  1058.     old = (char *)argv[arguments]; while (*new++ = *old++); 
  1059.   }
  1060.   
  1061.   if (strcmp(sep->se_server, "internal") == 0) {
  1062.     register struct biltin *bi;
  1063.  
  1064.     for (bi = biltins; bi->bi_service; bi++)
  1065.       if (bi->bi_socktype == sep->se_socktype &&
  1066.       strcmp(bi->bi_service, sep->se_service) == 0)
  1067.     break;
  1068.     if (bi->bi_service == 0) {
  1069.       syslog(LOG_ERR, "inetd: internal service %s unknown\n", sep->se_service);
  1070.       free(sep->se_service);
  1071.       goto more;
  1072.     }
  1073.     sep->se_bi = bi;
  1074.     sep->se_wait = bi->bi_wait;
  1075.   } else
  1076.     sep->se_bi = NULL;
  1077.  
  1078.   return (sep);
  1079. }
  1080.  
  1081. void
  1082. freeconfig(register struct servtab *cp)
  1083. {
  1084.   if (cp->se_service)
  1085.     free(cp->se_service);
  1086. }
  1087.  
  1088. /*
  1089.  * nextline
  1090.  *      get a CSource string containing next line
  1091.  */
  1092. struct CSource *
  1093. nextline(BPTR fh)
  1094. {
  1095.   size_t len = line.CS_Length = 0;
  1096.   UBYTE *buffer = line.CS_Buffer = linbuf;
  1097.   
  1098.   line.CS_CurChr = 0;
  1099.   
  1100.   for (;;) {
  1101.     linecnt++;
  1102.     if (FGets(fh, buffer + len, LINEBUFLEN - len - 1) == NULL) {
  1103.       if (IoErr()) {
  1104.     logdoserror("nextline");
  1105.     return NULL;
  1106.       }
  1107.       if (len == 0)
  1108.     return NULL;
  1109.     }
  1110.  
  1111.     len += strlen(buffer + len);
  1112.  
  1113.     /* a long line ? */
  1114.     if (len == LINEBUFLEN - 1 && buffer[LINEBUFLEN - 2] != '\n') {
  1115.       if (buffer[0] != '#') {
  1116.     SetIoErr(ERROR_LINE_TOO_LONG);
  1117.     logdoserror("nextline");
  1118.     return NULL;
  1119.       } else {
  1120.     /* A kludge for LONG comment lines */
  1121.     len = 1;
  1122.     linecnt--;
  1123.     continue;
  1124.       }
  1125.     }
  1126.  
  1127.     /* Check for a continued line */
  1128.     if (len > 1 && buffer[len - 2] != '+') {
  1129.       break;
  1130.     } else {
  1131.       /* current line continues */
  1132.       if (len > 2)
  1133.     len -= 2;
  1134.       else 
  1135.     len = 0;
  1136.     }
  1137.   }
  1138.   
  1139.   /*
  1140.    * Ensure that the line ends with '\n'.
  1141.    * This is required by AmigaDOS parsing functions.
  1142.    * There must be space for the newline, if there wouldn't,
  1143.    * the "long line" would have been caught above.
  1144.    */
  1145.   if (buffer[len - 1] != '\n') {
  1146.     buffer[len++] = '\n';
  1147.     buffer[len] = 0;
  1148.   }
  1149.   
  1150.   line.CS_Length = len;
  1151.   return &line;
  1152. }
  1153.  
  1154. /* 
  1155.  * logdoserror
  1156.  *     add the last DOS error into AmiTCP/IP log
  1157.  */
  1158. void 
  1159. logdoserror(const char *banner)
  1160. {
  1161.   LONG code = IoErr();
  1162.  
  1163.   if (linbuf && Fault(code, (UBYTE *)banner, linbuf, LINEBUFLEN)) {
  1164.     syslog(LOG_ERR, "inetd %s at line %ld\n", linbuf, linecnt);
  1165.   } else {
  1166.     syslog(LOG_ERR, "inetd %s: unknown DOS error %ld at line %ld\n", 
  1167.        code, linecnt);
  1168.   }
  1169. }
  1170.  
  1171.  
  1172. /*
  1173.  * Internet services provided internally by inetd:
  1174.  */
  1175.  
  1176. /* Echo service -- echo data back */
  1177. int
  1178. echo_stream(void *SocketBase, int s, struct servtab *sep)
  1179. {
  1180.   char buffer[BUFSIZE];
  1181.   int i;
  1182.  
  1183.   while ((i = recv(s, buffer, sizeof(buffer), 0)) > 0 &&
  1184.      send(s, buffer, i, 0) > 0)
  1185.     ;
  1186.   return 0;
  1187. }
  1188.  
  1189. /* Echo service -- echo data back */
  1190. int
  1191. echo_dg(void *SocketBase, int s, struct servtab *sep)
  1192. {
  1193.   char buffer[BUFSIZE];
  1194.   long i, size;
  1195.   struct sockaddr sa;
  1196.  
  1197.   size = sizeof(sa);
  1198.   if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  1199.     return 0;
  1200.   (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  1201.  
  1202.   return 0;
  1203. }
  1204.  
  1205. /* Discard service -- ignore data */
  1206. int
  1207. discard_stream(void *SocketBase, int s, struct servtab *sep)
  1208. {
  1209.   char buffer[BUFSIZE];
  1210.  
  1211.   while (recv(s, buffer, sizeof(buffer), 0) > 0)
  1212.     ;
  1213.  
  1214.   return 0;
  1215. }
  1216.  
  1217.  
  1218. /* Discard service -- ignore data */
  1219. int
  1220. discard_dg(void *SocketBase, int s, struct servtab *sep)
  1221. {
  1222.   char buffer[BUFSIZE];
  1223.  
  1224.   (void) recv(s, buffer, sizeof(buffer), 0);
  1225.   
  1226.   return 0;
  1227. }
  1228.  
  1229. #include <ctype.h>
  1230. #define LINESIZ 72
  1231. char ring[128];
  1232. char *endring = NULL;
  1233.  
  1234. void
  1235. initring(void)
  1236. {
  1237.   register int i;
  1238.  
  1239.   endring = ring;
  1240.  
  1241.   for (i = 0; i <= 128; ++i)
  1242.     if (isprint(i))
  1243.       *endring++ = i;
  1244. }
  1245.  
  1246. /* Character generator */
  1247. chargen_stream(void *SocketBase, int s, struct servtab *sep)
  1248. {
  1249.   register char *rs;
  1250.   long len;
  1251.   char text[LINESIZ+2];
  1252.  
  1253.   if (!endring) {
  1254.     initring();
  1255.   }
  1256.  
  1257.   text[LINESIZ] = '\r';
  1258.   text[LINESIZ + 1] = '\n';
  1259.   for (rs = ring;;) {
  1260.     if ((len = endring - rs) >= LINESIZ)
  1261.       bcopy(rs, text, LINESIZ);
  1262.     else {
  1263.       bcopy(rs, text, len);
  1264.       bcopy(ring, text + len, LINESIZ - len);
  1265.     }
  1266.     if (++rs == endring)
  1267.       rs = ring;
  1268.     if (send(s, text, sizeof(text), 0) != sizeof(text))
  1269.       break;
  1270.   }
  1271.  
  1272.   return 0;
  1273. }
  1274.  
  1275. /* Character generator */
  1276. chargen_dg(void *SocketBase, int s, struct servtab *sep)
  1277. {
  1278.   struct sockaddr sa;
  1279.   static char *rs;
  1280.   long len, size;
  1281.   char text[LINESIZ+2];
  1282.  
  1283.   if (endring == 0) {
  1284.     initring();
  1285.     rs = ring;
  1286.   }
  1287.  
  1288.   size = sizeof(sa);
  1289.   if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1290.     return 0;
  1291.  
  1292.   if ((len = endring - rs) >= LINESIZ)
  1293.     bcopy(rs, text, LINESIZ);
  1294.   else {
  1295.     bcopy(rs, text, len);
  1296.     bcopy(ring, text + len, LINESIZ - len);
  1297.   }
  1298.   if (++rs == endring)
  1299.     rs = ring;
  1300.   text[LINESIZ] = '\r';
  1301.   text[LINESIZ + 1] = '\n';
  1302.   (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1303.  
  1304.   return 0;
  1305. }
  1306.  
  1307. /*
  1308.  * Return a machine readable date and time, in the form of the
  1309.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1310.  * returns the number of seconds since midnight, Jan 1, 1970,
  1311.  * we must add 2208988800 seconds to this figure to make up for
  1312.  * some seventy years Bell Labs was asleep.
  1313.  */
  1314.  
  1315. long
  1316. machtime(void)
  1317. {
  1318.   struct timeval tv;
  1319.  
  1320.   if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1321.     /* fprintf(stderr, "Unable to get time of day\n"); */
  1322.     return (0L);
  1323.   }
  1324.   return (long)(htonl((long)tv.tv_sec + 2208988800));
  1325. }
  1326.  
  1327. int 
  1328. machtime_stream(void *SocketBase, int s, struct servtab *sep)
  1329. {
  1330.   long result;
  1331.  
  1332.   result = machtime();
  1333.   (void) send(s, (char *) &result, sizeof(result), 0);
  1334.  
  1335.   return 0;
  1336. }
  1337.  
  1338. machtime_dg(void *SocketBase, int s, struct servtab *sep)
  1339. {
  1340.   long result;
  1341.   struct sockaddr sa;
  1342.   long size;
  1343.  
  1344.   size = sizeof(sa);
  1345.   if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1346.     return 0;
  1347.   result = machtime();
  1348.   (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1349.  
  1350.   return 0;
  1351. }
  1352.  
  1353. /* Return human-readable time of day */
  1354. int
  1355. daytime_stream(void *SocketBase, int s, struct servtab *sep)
  1356. {
  1357.   char buffer[256];
  1358.   time_t time(), clock;
  1359.   char *ctime();
  1360.   
  1361.   clock = time((time_t *) 0);
  1362.   
  1363.   (void) strncpy(buffer, ctime(&clock), 24);   buffer[24] = '\0';
  1364.   (void) strcat(buffer, "\r\n");
  1365.   (void) send(s, buffer, strlen(buffer), 0);
  1366.   return 0;
  1367. }
  1368.  
  1369. /* Return human-readable time of day */
  1370. int
  1371. daytime_dg(void *SocketBase, int s, struct servtab *sep)
  1372. {
  1373.   char buffer[256];
  1374.   time_t time(), clock;
  1375.   struct sockaddr sa;
  1376.   long size;
  1377.  
  1378.   clock = time((time_t *) 0);
  1379.  
  1380.   size = sizeof(sa);
  1381.   if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1382.     return 0;
  1383.  
  1384.   (void) strncpy(buffer, ctime(&clock), 24);   buffer[24] = '\0';
  1385.   (void) strcat(buffer, "\r\n");
  1386.   (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1387.   return 0;
  1388. }
  1389.  
  1390. /*
  1391.  * Internal server stub 
  1392.  */
  1393. LONG SAVEDS start_builtin(void)
  1394. {
  1395.   struct Process *me = (struct Process *)FindTask(0L);
  1396.   struct DaemonMessage *dm = (struct DaemonMessage *)me->pr_ExitData;
  1397.   LONG retval = DERR_LIB; 
  1398.   void *SocketBase;
  1399.  
  1400.   if (SocketBase = OpenLibrary("bsdsocket.library", 2L)) {
  1401.     struct servtab *sep = (struct servtab *)dm->dm_Retval;
  1402.     int s = ObtainSocket(dm->dm_Id, AF_INET, sep->se_socktype, 0);
  1403.     if (s != -1) {
  1404.       dm->dm_Id = -1;
  1405.       retval = (*sep->se_bi->bi_fn)(SocketBase, s, sep);
  1406.     } else {
  1407.       retval = DERR_OBTAIN;
  1408.     }
  1409.     CloseLibrary(SocketBase);
  1410.   } 
  1411.  
  1412.   return retval;
  1413. }
  1414.  
  1415. /* 
  1416.  * setproctitle:
  1417.  *      set the process title
  1418.  */
  1419. void
  1420. setproctitle(char *a, int s)
  1421. {
  1422. #ifdef notyet
  1423.   int size;
  1424.   register char *cp;
  1425.   struct sockaddr_in sin;
  1426.   char buf[80];
  1427.   struct CSource csbuf;
  1428.   
  1429.   csbuf.CS_Buffer = buf;
  1430.   csbuf.CS_Length = sizeof(buf) - 1;
  1431.   csbuf.CS_CurChr = 0;
  1432.  
  1433.   size = sizeof(sin);
  1434.   if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) {
  1435.     struct MemList ml, *nml;
  1436.  
  1437.     (void) csprintf(csbuf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1438.  
  1439.     ml.ml_NumEntries = 1;
  1440.     ml.ml_ME[0].me_Reqs = MEMF_PUBLIC;
  1441.     ml.ml_ME[0].me_Length = csbuf.CS_CurChr + 1;
  1442.  
  1443.     /* A memlist entry is needed for automatic resource deallocation */
  1444.     if ((LONG)(nml = AllocEntry(&ml)) > 0) {
  1445.       struct Task *me = FindTask(NULL);
  1446.  
  1447.       cp = nml->ml_ME[1].me_Addr;
  1448.       buf[csbuf.CS_CurChr] = '\0';
  1449.       strcpy(cp, buf);
  1450.  
  1451.       /* Old name is pointer to se_service, so there is no need to free it */
  1452.       me->tc_Node.ln_Name = cp;
  1453.       Forbid();
  1454.       AddHead(&me->tc_MemEntry, nml);
  1455.       Permit();
  1456.     }
  1457.   }
  1458. #endif
  1459. }
  1460.  
  1461. /* 
  1462.  * proctitle:
  1463.  *     allocate a new process title 
  1464.  */
  1465. UBYTE *
  1466. proctitle(char *a, int s)
  1467. {
  1468.   long size;
  1469.   struct sockaddr_in sin;
  1470.   register char *cp;
  1471.   char buf[80];
  1472.   struct CSource csbuf;
  1473.   
  1474.   csbuf.CS_Buffer = buf;
  1475.   csbuf.CS_Length = sizeof(buf) - 1;
  1476.   csbuf.CS_CurChr = 0;
  1477.  
  1478.   size = sizeof(sin);
  1479.   if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) {
  1480.     (void) csprintf(&csbuf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1481.   } else {
  1482.     (void) csprintf(&csbuf, "%s", a); 
  1483.   }
  1484.   if (cp = AllocVec(csbuf.CS_CurChr + 1, MEMF_PUBLIC)) {
  1485.     buf[csbuf.CS_CurChr] = '\0';
  1486.     strcpy(cp, buf);
  1487.   }
  1488.   return cp;
  1489. }
  1490.  
  1491. #if __SASC
  1492. #define SysBase (*(struct ExecBase**)4)
  1493. /* 
  1494.  * Amiga process catcher
  1495.  */
  1496. ASM LONG
  1497. exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage)
  1498. {
  1499.   ((struct DaemonMessage *)exitmessage)->dm_Retval = status;
  1500.   ReplyMsg((struct Message *)exitmessage);
  1501.   return 0;
  1502. }
  1503.  
  1504. void
  1505. exitcode_end(void)
  1506. {
  1507. }
  1508. #undef SysBase
  1509.  
  1510. #define exitcode_len (((char *)exitcode_end)-((char *)exitcode))
  1511. #else
  1512. #error Unsupported compiler
  1513. #endif
  1514.  
  1515. void *WindowPtr = NULL;
  1516.  
  1517. /* 
  1518.  * Initialize Amiga Specific Features
  1519.  */
  1520. void 
  1521. amigainit(void)
  1522. {
  1523.   struct DaemonPort *dp, *dpo;
  1524.   BYTE msgbit;
  1525.   struct Process *me = (struct Process *)FindTask(NULL);
  1526.   int old_is_alive = 0;
  1527.  
  1528.   atexit(amigadeinit);
  1529.  
  1530.   /* Remove requesters */
  1531.   WindowPtr = me->pr_WindowPtr;
  1532.   me->pr_WindowPtr = (void *)-1L;
  1533.  
  1534.   if ((msgbit = AllocSignal(-1)) == -1) {
  1535.     (void)fprintf(stderr, "inetd: no free signals\n");
  1536.     exit(2);
  1537.   }
  1538.  
  1539.   /* Allocate a global port for DaemonMessages */
  1540.   if (dp = AllocVec(sizeof(*dp) + exitcode_len + sizeof(DAEMONPORTNAME),
  1541.             MEMF_CLEAR|MEMF_PUBLIC)) {
  1542.     dp->dp_Port.mp_Node.ln_Type = NT_MSGPORT;
  1543.     dp->dp_Port.mp_SigTask = me;
  1544.     dp->dp_Port.mp_Flags = PA_SIGNAL;
  1545.     dp->dp_Port.mp_SigBit = msgbit;
  1546.     memcpy(dp->dp_ExitCode = (char *)(dp + 1), exitcode, exitcode_len);
  1547.     memcpy(dp->dp_Port.mp_Node.ln_Name = exitcode_len + (UBYTE *)(dp + 1),
  1548.        DAEMONPORTNAME, sizeof(DAEMONPORTNAME));
  1549.     /* Flush copied function */
  1550.     CacheClearE(dp->dp_ExitCode, exitcode_len, CACRF_ClearI);
  1551.   }
  1552.  
  1553.   Forbid();
  1554.  
  1555.   dpo = (struct DaemonPort*)FindPort(DAEMONPORTNAME);
  1556.   if (!dpo) {
  1557.     if (dp) AddPort(dp);
  1558.   } else {
  1559.     FreeVec(dp);
  1560.     dp = dpo;
  1561.     if (dpo->dp_Port.mp_SigTask == NULL) {
  1562.       dpo->dp_Port.mp_SigTask = me;
  1563.       dpo->dp_Port.mp_SigBit = msgbit;
  1564.       dpo->dp_Port.mp_Flags = PA_SIGNAL;
  1565.       SetSignal(1 << msgbit, 1 << msgbit); /* check old messages */
  1566.     } else {
  1567.       old_is_alive = 1;
  1568.     }
  1569.   }
  1570.   Permit();
  1571.  
  1572.   if (old_is_alive || !dp) {
  1573.     FreeSignal(msgbit);
  1574.     (void)fprintf(stderr, old_is_alive ? 
  1575.           "inetd: already exists\n" :
  1576.           "inetd: memory exhausted\n");
  1577.     exit(2);
  1578.   }
  1579.  
  1580.   dport = dp;
  1581.  
  1582.   if (!(tport = CreateMsgPort())) {
  1583.     (void)fprintf(stderr, "inetd: could not create message port\n");
  1584.     exit(2);
  1585.   }
  1586.   if (!(tmsg = CreateIORequest(tport, sizeof(*tmsg)))){
  1587.     (void)fprintf(stderr, "inetd: could not create timer message\n");
  1588.     exit(2);
  1589.   }
  1590.  
  1591.   tmsg->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN; 
  1592.   tmsg->tr_node.io_Command = TR_ADDREQUEST;
  1593.  
  1594.   if (OpenDevice(TIMERNAME, UNIT_MICROHZ, 
  1595.          (struct IORequest *)tmsg, 0)) {
  1596.     (void)fprintf(stderr, "inetd: could not open %s\n", TIMERNAME);
  1597.     exit(2);
  1598.   }
  1599.   timer_is_open = 1;
  1600. }
  1601.  
  1602. /* 
  1603.  * Deinitialize Amiga Specific stuff
  1604.  */
  1605. void
  1606. amigadeinit(void)
  1607. {
  1608.   struct Process *me = (struct Process *)FindTask(NULL);
  1609.  
  1610.   /* Resume requesters for this process */
  1611.   me->pr_WindowPtr = WindowPtr;
  1612.  
  1613.   if (tmsg && timer_is_open) {
  1614.     if (tmsg->tr_node.io_Message.mn_Node.ln_Type != NT_UNKNOWN 
  1615.     && !CheckIO(tmsg)) {
  1616.       AbortIO(tmsg);
  1617.       WaitIO(tmsg);
  1618.     }
  1619.   }
  1620.   if (timer_is_open) {
  1621.     CloseDevice(tmsg);
  1622.     timer_is_open = 0;
  1623.   }
  1624.   if (tmsg) {
  1625.     DeleteIORequest(tmsg);
  1626.   }
  1627.   if (tport) {
  1628.     DeleteMsgPort(tport);
  1629.   }
  1630.  
  1631.   if (dport) {
  1632.     BYTE sigbit;
  1633.     int i;
  1634.  
  1635.     /* Try to kill all our builtin children */
  1636.     for (i = builtins_started - 1; i >= 0; i--)
  1637.       Signal((struct Task*)ptable[i], SIGBREAKF_CTRL_C);
  1638.     /* Close all sockets */
  1639.     for (i = NOFILE - 1; i >= 0; i--) {
  1640.       CloseSocket(i);
  1641.     }
  1642.     /* Wait until all childs are terminated */
  1643.     while (builtins_started > 0) {
  1644.       WaitPort(dport);
  1645.       reapchild();
  1646.     }
  1647.  
  1648.     Forbid();
  1649.     sigbit = dport->dp_Port.mp_SigBit;
  1650.     dport->dp_Port.mp_Flags = PA_IGNORE;
  1651.     dport->dp_Port.mp_SigBit = (UBYTE)-1; /* braindead */
  1652.     dport->dp_Port.mp_SigTask = NULL;
  1653.     FreeSignal(sigbit);
  1654.     Permit();
  1655.   }
  1656. }
  1657.  
  1658. /*
  1659.  * Generic printing functions 
  1660.  */
  1661. void ASM 
  1662. stuffchar(REG(d0) char ch, REG(a3) struct CSource * sc)
  1663. {
  1664.   if (sc->CS_CurChr < sc->CS_Length 
  1665.       && (sc->CS_Buffer[sc->CS_CurChr] = ch))
  1666.     sc->CS_CurChr++;
  1667. }
  1668.  
  1669. static ULONG
  1670. csprintf(struct CSource *buf, const char *fmt, ...)
  1671. {
  1672.   ULONG start = buf->CS_CurChr;
  1673.   va_list ap;
  1674.  
  1675.   if (buf->CS_Length && buf->CS_CurChr < buf->CS_Length) {
  1676.     va_start(ap, fmt);
  1677.     RawDoFmt((STRPTR)fmt, ap, stuffchar, buf);
  1678.     va_end(ap);
  1679.     
  1680.     if (buf->CS_CurChr == buf->CS_Length) {
  1681.       buf->CS_CurChr--;            /* must NUL terminate */
  1682.     }      
  1683.     buf->CS_Buffer[buf->CS_CurChr] = '\0';
  1684.  
  1685.     return buf->CS_CurChr - start;
  1686.   } else {
  1687.     /* A pathological case */
  1688.     return 0;
  1689.   }
  1690. }
  1691.